#! /usr/bin/env python
# -*- coding: utf-8 -*-

# @author: xmj
# @date: 2023/5/2

import time
import httpx
import logging
from progress.bar import ChargingBar


class SendRequest:

    def __init__(self, urls, is_auth, cup_auth, code):
        """
        :param urls: 请求url合集，类型是列表
        :param is_auth: 调用接口是否需要授权，1表示需要授权
        :param cup_auth: 从配置文件读取的cup-auth需要的认证内容，类型是字典
        :param code: 从配置文件读取的后端应该返回的响应码，后面会使用该响应码进行判断
        """
        # 请求总数
        self.code = code
        self.total_num = 0
        # 结果为正确的数量
        self.success_num = 0
        # 汇总所有请求的结果，结构如[{'code': 401, url: 'http://xxx', 'body': 'xxx', 'result': 'Fail'}, ]
        self.result = []
        self.urls = urls
        self.is_auth = is_auth
        self.cup_auth = cup_auth
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                          "Chrome/112.0.0.0 Safari/537.36",
        }
        # 为每个线程创建一个完成情况进度条
        self.bar = ChargingBar('Processing', max=len(self.urls))

    def send_get_request(self):
        """
        用于发送get请求，默认urls里面都是get请求，待后续完善endpoints.yml中的结构，添加内容来标识post请求
        :return:
        """
        # is_auth = 1, 需要把cup-auth的认证信息添加到header里面
        if self.is_auth == 1:
            if self.cup_auth['cookie'] != "":
                self.headers['cookie'] = self.cup_auth['cookie']
            if self.cup_auth['cup-auth'] != "":
                self.headers['cup-auth'] = self.cup_auth['cup-auth']
            if self.cup_auth['authorization'] != "":
                self.headers['authorization'] = self.cup_auth['authorization']
            logging.info("Enabled authorization, cookie: {}, cup-auth: {}, authorization: {}".format(
                self.cup_auth['cookie'], self.cup_auth['cup-auth'], self.cup_auth['authorization']
            ))
        # 开始循环请求接口
        for url in self.urls:
            try:
                logging.info("Request {}".format(url))
                start_time = time.time()
                data = httpx.get(url, headers=self.headers, verify=False)
                code = data.status_code
                body = data.text
                end_time = time.time()
                # 当请求/actuator/heapdump成功，会响应整个堆内存，如果直接写入日志会影响扫描的效率
                if code == 200 and "heapdump" in body:
                    body = "Heapdump can be got, click the url to get heapdump!!!!"
                logging.info("Response {}: {} {}, Execute Time: {}s".format(url, code, body[0: -1],
                                                                            round(end_time - start_time, 4)))
            except Exception as err:
                logging.error("Got exception: {}".format(err))
                code = 500
                body = 'Internal server error'
            self.total_num += 1
            # 如果响应的body长度大于200，则只显示前100个字符，为了减轻页面显示的压力。可以在日志里面查看完整的body内容
            if len(body) > 200:
                body = body[0: 100] + '...'
            if code == self.code:
                self.success_num += 1
                # 对直接返回html里面的<>进行转义处理，防止报告直接显示返回的html
                self.result.append({'code': code, 'url': url, 'body': body.replace('<', '&lt').replace('>', '&gt'),
                                    'result': 'Pass'})
            else:
                self.result.append({'code': code, 'url': url, 'body': body.replace('<', '&lt').replace('>', '&gt'),
                                    'result': 'Fail'})
            # 每发送一个请求，进度条走一格
            self.bar.next()
        # 所有请求发送完成之后结束进度条，进度走到100%
        self.bar.finish()
        return self.result, self.total_num, self.success_num

    def send_post_request(self):
        pass
